library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use work.constants.all;

entity sequencer2 is
    port(
		rst                : in  std_logic;
		clk              	 : in  std_logic;
		ale		  	 : out std_logic;
		psen		 	 : out std_logic;

		alu_op_code	 	 : out  std_logic_vector (3 downto 0);
		alu_src_1L		 : out  std_logic_vector (7 downto 0);
		alu_src_1H		 : out  std_logic_vector (7 downto 0);
		alu_src_2L		 : out  std_logic_vector (7 downto 0);
		alu_src_2H		 : out  std_logic_vector (7 downto 0);
		alu_by_wd		 : out  std_logic;             -- byte(0)/word(1) instruction
		alu_cy_bw		 : out  std_logic;             -- carry/borrow bit
		alu_ans_L		 : in std_logic_vector (7 downto 0);
		alu_ans_H		 : in std_logic_vector (7 downto 0);
		alu_cy		 	 : in std_logic;             -- carry out of bit 7/15
		alu_ac		 	 : in std_logic;		    -- carry out of bit 3/7
		alu_ov		 	 : in std_logic;		    -- overflow

		dividend_i		 : out  std_logic_vector(7 downto 0);
		divisor_i		 : out  std_logic_vector(7 downto 0);
		quotient_o		 : in std_logic_vector(7 downto 0); 
		remainder_o	 	 : in std_logic_vector(7 downto 0);
		div_done		 : in std_logic ;

		mul_a_i		 	 : out  std_logic_vector(7 downto 0);  -- Multiplicand
		mul_b_i		 	 : out  std_logic_vector(7 downto 0);  -- Multiplicator
		mul_prod_o 	 	 : in std_logic_vector(15 downto 0) ;-- Product

		i_ram_wrByte   	 : out std_logic; 
		i_ram_wrBit   	 : out std_logic; 
		i_ram_rdByte   	 : out std_logic; 
		i_ram_rdBit   	 : out std_logic; 
		i_ram_addr 	 	 : out std_logic_vector(7 downto 0); 
		i_ram_diByte  	 : out std_logic_vector(7 downto 0); 
		i_ram_diBit   	 : out std_logic; 
		i_ram_doByte   	 : in std_logic_vector(7 downto 0); 
		i_ram_doBit   	 : in std_logic; 
		
		i_rom_addr       : out std_logic_vector (15 downto 0);
		i_rom_data       : in  std_logic_vector (7 downto 0);
		i_rom_rd         : out std_logic;
		
		pc_debug	 	 : out std_logic_vector (15 downto 0);
		interrupt_flag	 : in  std_logic_vector (2 downto 0);
		erase_flag	 : out std_logic);

end sequencer2;

-------------------------------------------------------------------------------

architecture seq_arch of sequencer2 is

    type t_cpu_state is (T0, T1, T2, T3, T4, I0); --these determine whether you are in initialisation, state, normal execution state, etc
    type t_exe_state is (E0, E1, E2, E3, E4, E5, E6, E7, E8, E9, E10,E11, E12); --these are the equivalence T0, T1 in the lecture
    
	signal cpu_state 		: t_cpu_state;
    	signal exe_state 		: t_exe_state;
    	signal IR				: std_logic_vector(7 downto 0);		-- Instruction Register
	signal PC				: std_logic_vector(15 downto 0);	-- Program Counter
	signal AR				: std_logic_vector(7 downto 0);		-- Address Register
	signal DR				: std_logic_vector(7 downto 0);		-- Data Register
	signal int_hold			: std_logic;
	signal PSW				: std_logic_vector(7 DOWNTO 0);

begin

    process(rst, clk)
    begin
    if( rst = '1' ) then
		cpu_state <= T0;
		exe_state <= E0;
		ale <= '0'; psen <= '0';
		mul_a_i <= (others => '0'); mul_b_i <= (others => '0');
		dividend_i <= (others => '0'); divisor_i <= (others => '1');
		i_ram_wrByte <= '0'; i_ram_rdByte <= '0'; i_ram_wrBit <= '0'; i_ram_rdBit <= '0';
		IR <= (others => '0');
		PC <= (others => '0');
		--PC <= "0000000000100111";
		AR <= (others => '0');
		DR <= (others => '0');
		pc_debug <= (others => '1');
		int_hold <= '0';
		erase_flag <= '0';
		PSW <= "00000000";
    elsif (clk'event and clk = '1') then
		 case cpu_state is
			when T0 =>
				case exe_state is
					when E0	=>
					--FETCHING STATE
					-- Get PSW also, since it is used frequently
						i_ram_wrByte <= '0'; 
						i_ram_rdByte <= '1'; 
						i_ram_wrBit <= '0'; 
						i_ram_rdBit <= '0';
						i_ram_addr <= xD0; -- Get PSW
						
					-- Request instruction from ROM
						i_rom_addr <= PC;
						i_rom_rd <= '1';
					
					-- Update CPU states
						cpu_state <= T0;
						exe_state <= E1;

					when E1	=>
						PSW <= i_ram_doByte;
						IR <= i_rom_data;
						
					-- Update CPU states
						PC <= PC + 1;
						
						i_ram_wrByte <= '0'; 
						i_ram_rdByte <= '0'; 
						i_ram_wrBit <= '0'; 
						i_ram_rdBit <= '0';
						i_rom_rd <= '0';
						
						cpu_state <= T1;
						exe_state <= E0;
						
					when others =>	  
				end case;  

			when T1 =>
				case IR is 
					
					-- NOP
					when "00000000"  =>
						case exe_state is
							when E0	=>  	
								exe_state <= E1;
							when E1	=>  	
								exe_state <= E2;
							when E2	=>  	
								exe_state <= E3;
							when E3	=>  	
								exe_state <= E4;
							when E4	=>  	
								exe_state <= E5;
							when E5	=>  	
								exe_state <= E6;
							when E6	=>  	
								exe_state <= E7;
							when E7	=>  	
								exe_state <= E8;
							when E8	=>  	
								exe_state <= E9;
							when E9	=>
								exe_state <= E0;
								cpu_state <= T0;
							when others =>
								exe_state <= E0;
								cpu_state <= T0;
						end case;  
						
						
					-- MOV direct,A & Mov A,direct
					-- @Lin Lin
					
					when "11100101" | -- Mov A,direct
					"11110101" 			--Mov direct,A
					=>	
					case exe_state is
						
							when E0 =>	
								-- Read desired direct address from ROM
								i_rom_addr <= PC;
								i_rom_rd <= '1';					-- Load address to BUS
								-- Result is in i_rom_data								
								
								exe_state <= E1;
								
							when E1 =>
								PC <= PC + 1;	
								i_rom_rd <= '0';
								if(IR(4) = '0') then	-- direct to A, read direct value first
									i_ram_addr <= i_rom_data; 		-- Load direct to BUS			--put corresponding address into i ram address bus
								elsif(IR(4) = '1' )	then	-- A to direct, read A value first
									i_ram_addr <= xE0;		--set address to Accumulator	
								end if;			
								
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								
								
								DR <= i_ram_doByte;				-- Store the value for next step assignment
								
								-- Update states
								exe_state <= E2;
								
								
							when E2 =>		
								if(IR(4) = '0') then	-- direct to A, set to Accumulator for store
									i_ram_addr <= xE0;		--set address to Accumulator	
								elsif(IR(4) = '1' )	then	--A to direct, set to direct address for store
									i_ram_addr <= i_rom_data; 		-- Load direct to BUS			--put corresponding address into i ram address bus
								end if;			
								
								i_ram_wrByte <= '1';
								i_ram_wrBit  <= '0';
								i_ram_rdByte <= '0';
								i_ram_rdBit  <= '0';
								
								i_ram_diByte <= DR; 		-- move whatever value in Rn into the Accumulator
								
								exe_state <= E3;
								
								when E3 =>
								exe_state <= E4;
							when E4 =>
								exe_state <= E5;
							when E5 =>
								exe_state <= E6;
							when E6	=>  	
								exe_state <= E7;
							when E7	=>  	
								exe_state <= E8;
							when E8	=>  	
								exe_state <= E9;
							when E9	=>
								exe_state <= E0;
								cpu_state <= T0;
							when others =>
								exe_state <= E0;
								cpu_state <= T0;
								
						end case;
								
								
					
					-- MOV Rn,A & Mov A,Rn
					-- @Lin Lin
					
					when "11101000" | "11101001" | "11101010" | "11101011" | "11101100" | "11101101" | "11101110" | "11101111"
						|"11111000" | "11111001" | "11111010" | "11111011" | "11111100" | "11111101" | "11111110" | "11111111" =>	--Rn
						
						case exe_state is
							when E0 =>		
								--configure Rn address. Set write/read base on IR bit 4
								if(IR(5 downto 4) = "10") then	--Rn to A, read from Rn
									i_ram_addr <= "000" & i_ram_doByte(4 downto 3) & IR(2 DOWNTO 0);			--put corresponding address into i ram address bus
								elsif(IR(5 downto 4) = "11" )	then	-- A to Rn, write to Rn
									i_ram_addr <= xE0;		--set address to Accumulator	
								end if;
								
								--set read ram bytes since Rn is in the RAM
									i_ram_wrByte <= '0';
									i_ram_wrBit  <= '0';
									i_ram_rdByte <= '1';
									i_ram_rdBit  <= '0';		
									
								exe_state <= E1;
							
							when E1 =>		
								if(IR(5 downto 4) = "10") then
									i_ram_addr <= xE0;		--set address to Accumulator
								elsif(IR(5 downto 4) = "11") then
									i_ram_addr <= "000" & PSW(4 downto 3) & IR(2 DOWNTO 0);			--put corresponding address into i ram address bus
								end if;
								
								i_ram_wrByte <= '1';
								i_ram_wrBit  <= '0';
								i_ram_rdByte <= '0';
								i_ram_rdBit  <= '0';
								
								i_ram_diByte <= i_ram_doByte; 		-- move whatever value in Rn into the Accumulator
								
								exe_state <= E2;
							
							when E2 =>	
								exe_state <= E3;
							when E3 =>
								exe_state <= E4;
							when E4 =>
								exe_state <= E5;
							when E5 =>
								exe_state <= E6;
							when E6	=>  	
								exe_state <= E7;
							when E7	=>  	
								exe_state <= E8;
							when E8	=>  	
								exe_state <= E9;
							when E9	=>
								exe_state <= E0;
								cpu_state <= T0;
							when others =>
								exe_state <= E0;
								cpu_state <= T0;
								
						end case;
						
						
					-- ADD A,Rn & ADDC A,Rn & SUBB A.Rn
					when 	"00101000"|"00101001"|"00101010"|"00101011"|"00101100"|"00101101"|"00101110"|"00101111"|		-- ADD A,Rn
							"00111000"|"00111001"|"00111010"|"00111011"|"00111100"|"00111101"|"00111110"|"00111111"|		-- ADDC A,Rn
							"10011000"|"10011001"|"10011010"|"10011011"|"10011100"|"10011101"|"10011110"|"10011111"		-- SUBB A,Rn	
							=>
						case exe_state is
							when E0	=>  	
								-- Read ACC from RAM
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= xE0; 				-- Load ACC to BUS
								
								-- Disable ROM
								i_rom_rd <= '0';
								
								exe_state <= E1;
							when E1	=>  	
								-- Read Rn from RAM
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Load Rn to BUS
								i_ram_addr <= "000" & PSW(4 DOWNTO 3) & IR(2 DOWNTO 0);
								
								DR <= i_ram_doByte;	-- Store the ACC value first
								
								-- Disable ROM
								i_rom_rd <= '0';
								
								exe_state <= E2;
							when E2	=>  	
								-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';
								
								alu_by_wd <= '0';					-- Calculate only 1 byte
								
								-- Set Operation according to the operation type
								case IR(7 DOWNTO 4) is
									when "0010" =>					-- Add without carry
										alu_cy_bw 	<= '0';
										alu_op_code <= ALU_OPC_ADD;
									when "0011" =>					-- Add with carry
										alu_cy_bw 	<= PSW(7);
										alu_op_code <= ALU_OPC_ADC;
									when "1001" =>					-- Suub with Borrow
										alu_cy_bw 	<= PSW(7);
										alu_op_code <= ALU_OPC_SBB;										
									when others =>
										alu_cy_bw 	<= '0';
										alu_op_code <= ALU_OPC_ADD;
								end case;
								
								alu_src_1L <= DR;					-- Direct ACC to ALU
								alu_src_2L <= i_ram_doByte;	-- Direct Rn to ALU
								
								exe_state <= E3;
							when E3	=>  
								-- ALU result should be ready
								-- Store Result from ALU
								PSW(7) <= alu_cy;
								PSW(6) <= alu_ac;
								PSW(2) <= alu_ov;
								
								-- Update Result to ACC
								i_rom_rd <= '0';
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= xE0; 				-- Point to ACC
								i_ram_diByte <= alu_ans_L;	
								
								exe_state <= E4;
							when E4	=>
								-- Update new PSW
								i_rom_rd <= '0';
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= xD0; -- Point to PSW
								i_ram_diByte <= PSW;		
								
								exe_state <= E5;
							when E5	=>  	
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';
								exe_state <= E6;
							when E6	=>  	
								exe_state <= E7;
							when E7	=>  	
								exe_state <= E8;
							when E8	=>  	
								exe_state <= E9;
							when E9	=>
								exe_state <= E0;
								cpu_state <= T0;
							when others =>
								exe_state <= E0;
								cpu_state <= T0;
						end case;  
						
					-- ADD A,direct & ADDC A,direct & SUBB A,direct
					when	"00100101"|		-- ADD A,direct
							"00110101"|		-- ADDC A,direct
							"10010101"		-- SUBB A,direct
							=>
						case exe_state is
						
							when E0 =>			
								-- Read ACC from RAM
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= xE0; 				-- Load ACC to BUS
								
								-- Request direct address from ROM
								i_rom_addr <= PC;
								i_rom_rd <= '1';					-- Load address to BUS
																
								-- Update states
								exe_state <= E1;
						
							when E1 =>
								PC <= PC + 1;	
								i_rom_rd <= '0';
								
								-- Read (direct) from RAM
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= i_rom_data; 		-- Load direct to BUS
								
								DR <= i_ram_doByte;				-- Backup ACC first
								
								-- Update states
								exe_state <= E2;
							when E2	=>
								
								-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';
								
								-- Specify ALU operation settings
								alu_by_wd <= '0';					-- Calculate only 1 byte
								
								-- Set Operation according to the operation type
								case IR(7 DOWNTO 4) is
									when "0010" =>					-- Add without carry
										alu_cy_bw 	<= '0';
										alu_op_code <= ALU_OPC_ADD;
									when "0011" =>					-- Add with carry
										alu_cy_bw 	<= PSW(7);
										alu_op_code <= ALU_OPC_ADC;
									when "1001" =>					-- Suub with Borrow
										alu_cy_bw 	<= PSW(7);
										alu_op_code <= ALU_OPC_SBB;										
									when others =>
										alu_cy_bw 	<= '0';
										alu_op_code <= ALU_OPC_ADD;
								end case;
									
								alu_src_1L <= DR;					-- Direct ACC data to ALU
								alu_src_2L <= i_ram_doByte;	-- Direct (direct) to ALU
								
								-- Update states
								exe_state <= E3;
							
							when E3	=>	-- Update result to ACC
								-- ALU result should be ready
								-- Store Result from ALU
								PSW(7) <= alu_cy;
								PSW(6) <= alu_ac;
								PSW(2) <= alu_ov;
								
								-- Update Result to ACC
								i_rom_rd <= '0';
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= xE0; 				-- Point to ACC
								i_ram_diByte <= alu_ans_L;
								
								-- Update states
								exe_state <= E4;
								
							when E4	=>	-- Update new PSW
								i_rom_rd <= '0';
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= xD0; 				-- Point to PSW
								i_ram_diByte <= PSW;					
								
								-- Update States
								exe_state <= E5;
							when E5	=> 
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';
								exe_state <= E6;
							when E6	=>  	
								exe_state <= E7;
							when E7	=>  	
								exe_state <= E8;
							when E8	=>  	
								exe_state <= E9;
							when E9	=>
								exe_state <= E0;
								cpu_state <= T0;
							when others =>
								exe_state <= E0;
								cpu_state <= T0;
						end case;  						
						
					-- ADD A,@Ri & ADDC A,@Ri & SUBB A,@Ri
					when 	"00100110"|"00100111"|			-- ADD A,@Ri
							"00110110"|"00110111"|			-- ADDC A,@Ri
							"10010110"|"10010111"			-- SUBB A,@Ri
							=>
						case exe_state is
							when E0	=>  	
								-- Read ACC from RAM
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= xE0; 				-- Load ACC to BUS
								
								-- Disable ROM
								i_rom_rd <= '0';
								
								exe_state <= E1;
							when E1	=>  	
								-- Read Ri from RAM
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Load Ri to BUS
								i_ram_addr <= "000" & PSW(4 DOWNTO 3) & "00" & IR(0); 		
								
								DR <= i_ram_doByte;	-- Store the ACC value first
								
								-- Disable ROM
								i_rom_rd <= '0';
								
								exe_state <= E2;
							when E2	=>
								-- Read Real Data from RAM
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Load ((Ri)) to BUS
								i_ram_addr <= i_ram_doByte;	-- Using whatever stored in the Ri
								
								-- Disable ROM
								i_rom_rd <= '0';
								
								exe_state <= E3;
							when E3	=>  	
								-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';
								
								alu_by_wd <= '0';					-- Calculate only 1 byte
								
								-- Specify ALU operation settings
								alu_by_wd <= '0';					-- Calculate only 1 byte
								
								alu_cy_bw 	<= PSW(7);
								-- Set Operation according to the operation type
								case IR(7 DOWNTO 4) is
									when "0010" =>					-- Add without carry
										alu_op_code <= ALU_OPC_ADD;
									when "0011" =>					-- Add with carry
										alu_op_code <= ALU_OPC_ADC;
									when "1001" =>					-- Suub with Borrow
										alu_op_code <= ALU_OPC_SBB;										
									when others =>
										alu_op_code <= ALU_OPC_ADD;
								end case;
								
								alu_src_1L <= DR;					-- Direct ACC to ALU
								alu_src_2L <= i_ram_doByte;	-- Direct ((Ri)) to ALU
								
								exe_state <= E4;
							when E4	=>  
								-- ALU result should be ready
								-- Store Result from ALU
								PSW(7) <= alu_cy;
								PSW(6) <= alu_ac;
								PSW(2) <= alu_ov;
								
								-- Update Result to ACC
								i_rom_rd <= '0';
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= xE0; 				-- Point to ACC
								i_ram_diByte <= alu_ans_L;	
								
								exe_state <= E5;
							when E5	=>
								-- Update new PSW
								i_rom_rd <= '0';
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= xD0; 				-- Point to PSW
								i_ram_diByte <= PSW;		
								
								exe_state <= E6;
							when E6	=>  	
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';
								exe_state <= E7;
							when E7	=>  	
								exe_state <= E8;
							when E8	=>  	
								exe_state <= E9;
							when E9	=>
								exe_state <= E0;
								cpu_state <= T0;
							when others =>
								exe_state <= E0;
								cpu_state <= T0;
						end case;  
						
					-- ADD A,#data & ADDC A,#data & SUBB A, #data
					-- instruction .. #data
					when 	"00100100"|		--  ADD A,#data
							"00110100"|		--  ADDC A,#data
							"10010100"		--  SUBB A, #data
							=>
						case exe_state is
						
							when E0 =>			
								-- Read ACC from RAM and directed to ALU src1
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= xE0; 				-- Load ACC to BUS
								
								-- Request #data from ROM and directed to ALU src2
								i_rom_addr <= PC;
								i_rom_rd <= '1';					-- Load #data to BUS
																
								-- Update states
								exe_state <= E1;
						
							when E1	=>
								PC <= PC + 1;	
								
								-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';
								
								-- Specify ALU operation settings
								alu_by_wd <= '0';					-- Calculate only 1 byte
								
								-- Set Operation according to the operation type
								case IR(7 DOWNTO 4) is
									when "0010" =>					-- Add without carry
										alu_cy_bw 	<= '0';
										alu_op_code <= ALU_OPC_ADD;
									when "0011" =>					-- Add with carry
										alu_cy_bw 	<= PSW(7);
										alu_op_code <= ALU_OPC_ADC;
									when "1001" =>					-- Suub with Borrow
										alu_cy_bw 	<= PSW(7);
										alu_op_code <= ALU_OPC_SBB;										
									when others =>
										alu_cy_bw 	<= '0';
										alu_op_code <= ALU_OPC_ADD;
								end case;
								
								alu_src_1L <= i_ram_doByte;	-- Direct ACC to ALU
								alu_src_2L <= i_rom_data;		-- Direct #Data to ALU
								
								-- Update states
								exe_state <= E2;
							
							when E2	=>	-- Update result to ACC
								-- ALU result should be ready
								-- Store Result from ALU
								PSW(7) <= alu_cy;
								PSW(6) <= alu_ac;
								PSW(2) <= alu_ov;
								
								-- Update Result to ACC
								i_rom_rd <= '0';
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= xE0; 				-- Point to ACC
								i_ram_diByte <= alu_ans_L;
								
								-- Update states
								exe_state <= E3;
								
							when E3	=>	-- Update new PSW
								i_rom_rd <= '0';
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= xD0; -- Point to PSW
								i_ram_diByte <= PSW;					
								
								-- Update States
								exe_state <= E4;
							when E4	=> 
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';
								exe_state <= E5;
							when E5	=>  	
								exe_state <= E6;
							when E6	=>  	
								exe_state <= E7;
							when E7	=>  	
								exe_state <= E8;
							when E8	=>  	
								exe_state <= E9;
							when E9	=>
								exe_state <= E0;
								cpu_state <= T0;
							when others =>
								exe_state <= E0;
								cpu_state <= T0;
						end case;  		
					
					-- DEC A & INC A
					when 	"00010100"|		-- DEC A
							"00000100"		-- INC A
							=>
						case exe_state is
							when E0	=>  	
							-- Read ACC from RegFile
								i_rom_rd <= '0';
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= xE0; 				-- Load ACC to BUS
								
								exe_state <= E1;
							when E1	=>  	
							-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';
								
								-- Specify ALU operation settings
								alu_by_wd <= '0';					-- Calculate only 1 byte
								alu_cy_bw 	<= '0';
								
								-- Set Operation according to the operation type
								case IR(7 DOWNTO 4) is
									when "0001" =>					-- Add without carry
										alu_op_code <= ALU_OPC_DEC;
									when "0000" =>					-- Add with carry
										alu_op_code <= ALU_OPC_INC;									
									when others =>
										alu_op_code <= ALU_OPC_INC;
								end case;
								
								alu_src_1L <= i_ram_doByte;	-- Direct ACC to ALU
								alu_src_2L <= (others => '0');		-- Direct #Data to ALU
								
								exe_state <= E2;
							when E2	=>  	
								-- Update Result to ACC
								i_rom_rd <= '0';
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= xE0; 				-- Point to ACC
								i_ram_diByte <= alu_ans_L;
								
								exe_state <= E3;
							when E3	=>  	
								-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';
								
								exe_state <= E4;
							when E4	=>  	
								exe_state <= E5;
							when E5	=>  	
								exe_state <= E6;
							when E6	=>  	
								exe_state <= E7;
							when E7	=>  	
								exe_state <= E8;
							when E8	=>  	
								exe_state <= E9;
							when E9	=>
								exe_state <= E0;
								cpu_state <= T0;
							when others =>
								exe_state <= E0;
								cpu_state <= T0;
						end case;  				

					-- DEC Rn & INC Rn
					when 	"00011000"|"00011001"|"00011010"|"00011011"|"00011100"|"00011101"|"00011110"|"00011111"|		-- DEC Rn
							"00001000"|"00001001"|"00001010"|"00001011"|"00001100"|"00001101"|"00001110"|"00001111"		-- INC Rn
							=>
						case exe_state is
							when E0	=>  	
							-- Read Rn from RAM
								i_rom_rd <= '0';
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Load Rn to BUS
								i_ram_addr <= "000" & PSW(4 DOWNTO 3) & IR(2 DOWNTO 0);
								
								exe_state <= E1;
							when E1	=>  	
							-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';
								
								-- Specify ALU operation settings
								alu_by_wd <= '0';					-- Calculate only 1 byte
								alu_cy_bw 	<= '0';
								
								-- Set Operation according to the operation type
								case IR(7 DOWNTO 4) is
									when "0001" =>					-- Add without carry
										alu_op_code <= ALU_OPC_DEC;
									when "0000" =>					-- Add with carry
										alu_op_code <= ALU_OPC_INC;									
									when others =>
										alu_op_code <= ALU_OPC_INC;
								end case;
								
								alu_src_1L <= i_ram_doByte;	-- Direct Rn to ALU
								alu_src_2L <= (others => '0');		
								
								exe_state <= E2;
							when E2	=>  	
							-- Update new Rn to RAM
								i_rom_rd <= '0';
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- put new Rn to RAM
								i_ram_addr <= "000" & PSW(4 DOWNTO 3) & IR(2 DOWNTO 0);
								i_ram_diByte <= alu_ans_L;
								
								exe_state <= E3;
							when E3	=>  	
								-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';
								
								exe_state <= E4;
							when E4	=>  	
								exe_state <= E5;
							when E5	=>  	
								exe_state <= E6;
							when E6	=>  	
								exe_state <= E7;
							when E7	=>  	
								exe_state <= E8;
							when E8	=>  	
								exe_state <= E9;
							when E9	=>
								exe_state <= E0;
								cpu_state <= T0;
							when others =>
								exe_state <= E0;
								cpu_state <= T0;
						end case;  				

					-- DEC direct & INC direct
					when 	"00010101"|		-- DEC direct
							"00000101"		-- INC direct
							=>
						case exe_state is
							when E0	=>  	
							-- Read Direct Address from ROM
								i_rom_rd <= '1';
								i_rom_addr <= PC;
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Load Direct address to BUS
								
								exe_state <= E1;
								
							when E1	=>  	
								PC <= PC + 1;
								-- Update PC after reading
								AR <= i_rom_data;
								
							-- Read data from RAM
								i_rom_rd <= '0';
								i_ram_addr <= i_rom_data;
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Load data to BUS
								
								exe_state <= E2;
								
							when E2 =>
							-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';
								
								-- Specify ALU operation settings
								alu_by_wd <= '0';					-- Calculate only 1 byte
								alu_cy_bw 	<= '0';
								
								-- Set Operation according to the operation type
								case IR(7 DOWNTO 4) is
									when "0001" =>					-- Add without carry
										alu_op_code <= ALU_OPC_DEC;
									when "0000" =>					-- Add with carry
										alu_op_code <= ALU_OPC_INC;									
									when others =>
										alu_op_code <= ALU_OPC_INC;
								end case;
								
								alu_src_1L <= i_ram_doByte;	-- Direct data to ALU
								alu_src_2L <= (others => '0');		
								
								exe_state <= E3;
							when E3	=>  	
							-- Update new data to Direct Address
								i_rom_rd <= '0';
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- put new Rn to RAM
								i_ram_addr <= AR;
								i_ram_diByte <= alu_ans_L;
								
								exe_state <= E4;
							when E4	=>  	
								-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';
								  	
								exe_state <= E5;
							when E5	=>  	
								exe_state <= E6;
							when E6	=>  	
								exe_state <= E7;
							when E7	=>  	
								exe_state <= E8;
							when E8	=>  	
								exe_state <= E9;
							when E9	=>
								exe_state <= E0;
								cpu_state <= T0;
							when others =>
								exe_state <= E0;
								cpu_state <= T0;
						end case;  				

					-- DEC @Ri & INC @Ri
					when 	"00010110"|"00010111"|		-- DEC @Ri
							"00000110"|"00000111"		-- INC @Ri
							=>
						case exe_state is
							when E0	=>  	
							-- Read Ri from RAM
								i_rom_rd <= '0';
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Load Ri to BUS
								i_ram_addr <= "000" & PSW(4 DOWNTO 3) & "00" & IR(0);
								
								exe_state <= E1;
								
							when E1	=>  	
								-- Update PC after reading
								AR <= i_ram_doByte;
								
							-- Read Real Data from RAM
								i_rom_rd <= '0';
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Load ((Ri)) to BUS
								i_ram_addr <= i_ram_doByte;	-- Using whatever stored in the Ri
								AR <= i_ram_doByte;
								
								exe_state <= E2;
								
							when E2 =>
							-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';
								
								-- Specify ALU operation settings
								alu_by_wd <= '0';					-- Calculate only 1 byte
								alu_cy_bw 	<= '0';
								
								-- Set Operation according to the operation type
								case IR(7 DOWNTO 4) is
									when "0001" =>					-- Add without carry
										alu_op_code <= ALU_OPC_DEC;
									when "0000" =>					-- Add with carry
										alu_op_code <= ALU_OPC_INC;									
									when others =>
										alu_op_code <= ALU_OPC_INC;
								end case;
								
								alu_src_1L <= i_ram_doByte;	-- Direct data to ALU
								alu_src_2L <= (others => '0');		
								
								exe_state <= E3;
							when E3	=>  	
							-- Update new data to Direct Address
								i_rom_rd <= '0';
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- put new Rn to RAM
								i_ram_addr <= AR;
								i_ram_diByte <= alu_ans_L;
								
								exe_state <= E4;
							when E4	=>  	
								-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';
								  	
								exe_state <= E5;
							when E5	=>  	
								exe_state <= E6;
							when E6	=>  	
								exe_state <= E7;
							when E7	=>  	
								exe_state <= E8;
							when E8	=>  	
								exe_state <= E9;
							when E9	=>
								exe_state <= E0;
								cpu_state <= T0;
							when others =>
								exe_state <= E0;
								cpu_state <= T0;
						end case;  				
						
					-- INC DPTR
					when 	"10100011"		-- INC @Ri
							=>
						case exe_state is
							when E0	=>  	
							-- Read DPL
								i_rom_rd <= '0';
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Load DPL to BUS
								i_ram_addr <= x82;
								
								exe_state <= E1;
								
							when E1	=>  	
							-- Increase DPL
								alu_src_1L <= i_ram_doByte;	-- Direct DPL to ALU
								alu_src_2L <= (others => '0');
								alu_by_wd <= '0';					-- Calculate only 1 byte
								alu_cy_bw 	<= '0';
								alu_op_code <= ALU_OPC_INC;	-- Increase the DPL
								
							-- Read DPH from Registers File
								i_rom_rd <= '0';
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Load DPH to BUS
								i_ram_addr <= x83;
								
								exe_state <= E2;
								
							when E2 =>
							-- Write back new DTL
								i_rom_rd <= '0';
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Write new DPL back to register
								i_ram_addr <= x82;
								i_ram_diByte <= alu_ans_L;
								
							-- Update the DPH
								alu_src_1L <= i_ram_doByte;	-- Direct DPH to ALU
								alu_src_2L <= (others => '0');
								alu_by_wd <= '0';					-- Calculate only 1 byte
								alu_cy_bw 	<= alu_cy;
								alu_op_code <= ALU_OPC_ADC;	-- Increase the DPL
							
								exe_state <= E3;
							when E3	=>
							-- Write back new DTH
								i_rom_rd <= '0';
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Write new DPL back to register
								i_ram_addr <= x83;
								i_ram_diByte <= alu_ans_L;
								
								exe_state <= E4;
							when E4	=>  	
								-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';
								  	
								exe_state <= E5;
							when E5	=>  	
								exe_state <= E6;
							when E6	=>  	
								exe_state <= E7;
							when E7	=>  	
								exe_state <= E8;
							when E8	=>  	
								exe_state <= E9;
							when E9	=>
								exe_state <= E0;
								cpu_state <= T2;
							when others =>
								exe_state <= E0;
								cpu_state <= T0;
						end case;
						
					-- MUL AB
					when 	"10100100"		-- MUL AB
							=>
						case exe_state is
							when E0	=>  	
							-- Read Acc
								i_rom_rd <= '0';
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Load Acc to BUS
								i_ram_addr <= xE0;
								
								exe_state <= E1;
								
							when E1	=>  
							-- Store the retrieve Acc first
								DR<=i_ram_doByte;
								
							-- Read B from Registers File
								i_rom_rd <= '0';
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Load B to BUS
								i_ram_addr <= xF0;
								
								exe_state <= E2;
								
							when E2 =>		
							-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';	
								
							-- Multiply Acc and B
								mul_a_i <= DR;
								mul_b_i <= i_ram_doByte;
							
								exe_state <= E3;
							when E3	=>
							-- Write LSB answer to Acc first
								i_rom_rd <= '0';
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Write new DPL back to register
								i_ram_addr <= xE0;
								i_ram_dibyte <= mul_prod_o(7 Downto 0);
								
								exe_state <= E4;
							when E4	=>  	
							-- Write MSB answer to B now
								i_rom_rd <= '0';
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Write new DPL back to register
								i_ram_addr <= xF0;
								i_ram_dibyte <= mul_prod_o(15 Downto 8);
								  	
								exe_state <= E5;
							when E5	=>  	
								-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';
								exe_state <= E6;
							when E6	=>  	
								exe_state <= E7;
							when E7	=>  	
								exe_state <= E8;
							when E8	=>  	
								exe_state <= E9;
							when E9	=>
								exe_state <= E0;
								cpu_state <= T2;
							when others =>
								exe_state <= E0;
								cpu_state <= T0;
						end case;
					
					-- DIV AB
					when 	"10000100"		-- DIV AB
							=>
						case exe_state is
							when E0	=>  	
							-- Read Acc
								i_rom_rd <= '0';
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Load Acc to BUS
								i_ram_addr <= xE0;
								
								exe_state <= E1;
								
							when E1	=>  
							-- Store the retrieve Acc first
								DR<=i_ram_doByte;
								
							-- Read B from Registers File
								i_rom_rd <= '0';
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Load B to BUS
								i_ram_addr <= xF0;
								
								exe_state <= E2;
								
							when E2 =>
							-- Backup B register value in case
								AR <= i_ram_doByte;
								
							-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';	
								
							-- Divide Acc with B
								dividend_i <= DR;
								divisor_i <= i_ram_doByte;
							-- Wait for 8 cycle while divisor is preforming division
							
								exe_state <= E3;
							when E3	=>
							-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';	
								
								exe_state <= E4;
							when E4	=> 
								exe_state <= E5;
							when E5	=> 
								exe_state <= E6;
							when E6	=>  	
								exe_state <= E7;
							when E7	=>  	
								exe_state <= E8;
							when E8	=>  	
								exe_state <= E9;
							when E9	=>
								exe_state <= E0;
								cpu_state <= T2;
							when others =>
								exe_state <= E0;
								cpu_state <= T0;
						end case;
						
					-- DA A
					when 	"11010100"		-- DA A
							=>
						case exe_state is
							when E0	=>  	
							-- Read Acc
								i_rom_rd <= '0';
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Load Acc to BUS
								i_ram_addr <= xE0;
								
								exe_state <= E1;
								
							when E1	=> 	
							-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';
							
							-- Handle the LSB first
							-- Specify ALU operation settings
								alu_by_wd <= '0';					-- Calculate only 1 byte
								alu_cy_bw 	<= '0';
								alu_op_code <= ALU_OPC_ADD;
								
								alu_src_1L <= i_ram_doByte;	-- Direct Acc to ALU
								if (i_ram_doByte(3 Downto 0) >"1001" or PSW(6)='1') then
									-- Plus 6 to Lower 4 bits.
									alu_src_2L <= "00000110";
								else
									alu_src_2L <= (others => '0');
								end if;
								
								exe_state <= E2;
								
							when E2 =>
							-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';
								
							-- Check previous adding result
							
								if(alu_cy='1') then
									PSW(7)<='1';
								end if;
								
							-- Handle the next MSB
							-- Specify ALU operation settings
								alu_by_wd <= '0';					-- Calculate only 1 byte
								alu_cy_bw 	<= '0';
								alu_op_code <= ALU_OPC_ADD;
								
								alu_src_1L <= alu_ans_L;	-- Direct Acc to ALU
								if(alu_ans_L(7 Downto 4)>"1001" or alu_cy='1' or PSW(7)='1') then
									alu_src_2L <= "01100000";
								else
									alu_src_2L <= (others => '0');
								end if;
								
								exe_state <= E3;
							when E3	=>
							-- Write converted Acc back to memory
								i_rom_rd <= '0';	
								
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= xE0;
								i_ram_dibyte <= alu_ans_L;
								
								if(alu_cy='1') then
									PSW(7)<='1';
								end if;
								
								exe_state <= E4;
							when E4	=> 
							
							-- Update new PSW
								i_rom_rd <= '0';
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= xD0; -- Point to PSW
								i_ram_diByte <= PSW;		
								
								exe_state <= E5;
							when E5	=> 
							-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';	
								exe_state <= E6;
							when E6	=>  	
								exe_state <= E7;
							when E7	=>  	
								exe_state <= E8;
							when E8	=>  	
								exe_state <= E9;
							when E9	=>
								exe_state <= E0;
								cpu_state <= T2;
							when others =>
								exe_state <= E0;
								cpu_state <= T0;
						end case;
						
					-- ACALL addr11
					when 	"00010001"|"00110001"|"01010001"|"01110001"|		-- ACALL addr11
							"10010001"|"10110001"|"11010001"|"11110001"
							=>
						case exe_state is
							when E0	=>  	
							-- Load Stack Pointer first
							-- Load Address info in ROM also
								i_rom_rd <= '1';
								i_rom_addr <= PC;
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Load Stack Pointer to BUS
								i_ram_addr <= x81;
								
							-- Update PC value at the same time
								PC<= PC+1;
								
								exe_state <= E1;
								
							when E1	=> 	
							-- Retrieve the Jumping Location
								DR <= i_rom_data;
								
							-- Increase SP to point to final location
								AR <= i_ram_doByte + 2;
							
							-- Write PC(7 Downto 0) to SP+1
								i_rom_rd <= '0';								
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= i_ram_doByte+1;
								i_ram_dibyte <= PC(7 Downto 0);
								
								exe_state <= E2;
								
							when E2 =>
							-- Write PC(15 Downto 8) to SP+2
								i_rom_rd <= '0';								
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= AR;
								i_ram_dibyte <= PC(15 Downto 8);
								
								exe_state <= E3;
							when E3	=>
							-- Write New SP back to reg file
								i_rom_rd <= '0';	
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= x81;
								i_ram_dibyte <= AR;
								
							-- Update the PC value
								PC <= PC(15 Downto 11) & IR(7 Downto 5) & DR;
								
								exe_state <= E4;
							when E4	=> 
							-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';		
								
								exe_state <= E5;
							when E5	=> 
							-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';	
								exe_state <= E6;
							when E6	=>
								exe_state <= E7;
							when E7	=>  	
								exe_state <= E8;
							when E8	=>  	
								exe_state <= E9;
							when E9	=>
								exe_state <= E0;
								cpu_state <= T2;
							when others =>
								exe_state <= E0;
								cpu_state <= T0;
						end case;
						
					-- LCALL addr16
					when 	"00010010"		-- LCALL addr16
							=>
						case exe_state is
							when E0	=>
							-- Load Stack Pointer first
							-- Load Address info in ROM also
								i_rom_rd <= '1';
								i_rom_addr <= PC;
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '1'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Load Stack Pointer to BUS
								i_ram_addr <= x81;
								
							-- Update PC value at the same time
								PC <= PC+1;
								
								exe_state <= E1;
								
							when E1	=> 	
							-- Retrieve the Jumping Location(MSB)
								AR <= i_rom_data;
							
							-- Write PC(7 Downto 0) to SP+1
								i_rom_rd <= '0';								
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= i_ram_doByte+1;
								i_ram_dibyte <= PC(7 Downto 0);
								
								exe_state <= E2;
								
							when E2 =>
							-- Write PC(15 Downto 8) to SP+2
								i_rom_rd <= '0';								
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= AR;
								i_ram_dibyte <= PC(15 Downto 8);
								
								exe_state <= E3;
							when E3	=>
							-- Write New SP back to reg file
								i_rom_rd <= '0';	
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= x81;
								i_ram_dibyte <= AR;
								
							-- Update the PC value
								PC <= PC(15 Downto 11) & IR(7 Downto 5) & DR;
								
								exe_state <= E4;
							when E4	=> 
							-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';		
								
								exe_state <= E5;
							when E5	=> 
							-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';	
								exe_state <= E6;
							when E6	=>
								exe_state <= E7;
							when E7	=>  	
								exe_state <= E8;
							when E8	=>  	
								exe_state <= E9;
							when E9	=>
								exe_state <= E0;
								cpu_state <= T2;
							when others =>
								exe_state <= E0;
								cpu_state <= T0;
						end case;
				when others => 		exe_state <= E0;	
											cpu_state <= T0;
			end case;
			
		-- My adding, IO missing
		when T2 =>
			case IR is
					-- INC DPTR
					when 	"10100011"		-- INC @Ri
							=>
					case exe_state is
						when E0 =>
							exe_state <= E1;
							cpu_state <= T2;
						when E1 =>
							exe_state <= E2;
							cpu_state <= T2;
						when E2 =>
							exe_state <= E3;
							cpu_state <= T2;
						when E3 =>
							exe_state <= E4;
							cpu_state <= T2;
						when E4 =>
							exe_state <= E5;
							cpu_state <= T2;
						when E5 =>
							exe_state <= E6;
							cpu_state <= T2;
						when E6 =>
							exe_state <= E7;
							cpu_state <= T2;
						when E7 =>
							exe_state <= E8;
							cpu_state <= T2;
						when E8 =>
							exe_state <= E9;
							cpu_state <= T2;
						when E9 =>
							exe_state <= E10;
							cpu_state <= T2;
						when E10 =>
							exe_state <= E11;
							cpu_state <= T2;
						when E11 =>
							exe_state <= E0;
							cpu_state <= T0;
						when others =>
							exe_state <= E0;
							cpu_state <= T0;		
					end case;
					
					-- MUL AB
					when 	"10100100"		-- MUL AB
							=>
					case exe_state is
						when E0 =>
							exe_state <= E1;
							cpu_state <= T2;
						when E1 =>
							exe_state <= E2;
							cpu_state <= T2;
						when E2 =>
							exe_state <= E3;
							cpu_state <= T2;
						when E3 =>
							exe_state <= E4;
							cpu_state <= T2;
						when E4 =>
							exe_state <= E5;
							cpu_state <= T2;
						when E5 =>
							exe_state <= E6;
							cpu_state <= T2;
						when E6 =>
							exe_state <= E7;
							cpu_state <= T2;
						when E7 =>
							exe_state <= E8;
							cpu_state <= T2;
						when E8 =>
							exe_state <= E9;
							cpu_state <= T2;
						when E9 =>
							exe_state <= E10;
							cpu_state <= T2;
						when E10 =>
							exe_state <= E11;
							cpu_state <= T2;
						when E11 =>
							exe_state <= E0;
							cpu_state <= T3;
						when others =>
							exe_state <= E0;
							cpu_state <= T0;		
					end case;
					
				-- DIV AB
					when 	"10000100"		-- DIV AB
							=>   -- continue wait for result in this state
						case exe_state is
						when E0 =>
							exe_state <= E1;
							cpu_state <= T2;
						when E1 =>
							exe_state <= E2;
							cpu_state <= T2;
						when E2 =>
							exe_state <= E3;
							cpu_state <= T2;
						when E3 =>
							exe_state <= E4;
							cpu_state <= T2;
						when E4 =>
							exe_state <= E5;
							cpu_state <= T2;
						when E5 =>
							exe_state <= E6;
							cpu_state <= T2;
						when E6 =>
							exe_state <= E7;
							cpu_state <= T2;
						when E7 =>
							exe_state <= E8;
							cpu_state <= T2;
						when E8 =>
							exe_state <= E9;
							cpu_state <= T2;
						when E9 =>
							exe_state <= E10;
							cpu_state <= T2;
						when E10 =>
							exe_state <= E11;
							cpu_state <= T2;
						when E11 =>
							exe_state <= E0;
							cpu_state <= T3;
						when others =>
							exe_state <= E0;
							cpu_state <= T0;		
					end case;
					
				-- ACALL addr11
					when 	"00010001"|"00110001"|"01010001"|"01110001"|		-- ACALL addr11
							"10010001"|"10110001"|"11010001"|"11110001"
							=>
							case exe_state is
						when E0 =>
							exe_state <= E1;
							cpu_state <= T2;
						when E1 =>
							exe_state <= E2;
							cpu_state <= T2;
						when E2 =>
							exe_state <= E3;
							cpu_state <= T2;
						when E3 =>
							exe_state <= E4;
							cpu_state <= T2;
						when E4 =>
							exe_state <= E5;
							cpu_state <= T2;
						when E5 =>
							exe_state <= E6;
							cpu_state <= T2;
						when E6 =>
							exe_state <= E7;
							cpu_state <= T2;
						when E7 =>
							exe_state <= E8;
							cpu_state <= T2;
						when E8 =>
							exe_state <= E9;
							cpu_state <= T2;
						when E9 =>
							exe_state <= E10;
							cpu_state <= T2;
						when E10 =>
							exe_state <= E11;
							cpu_state <= T2;
						when E11 =>
							exe_state <= E0;
							cpu_state <= T0;
						when others =>
							exe_state <= E0;
							cpu_state <= T0;		
						end case;
				when others => 
					exe_state <= E0;
					cpu_state <= T0;	
			end case;
		when T3 =>
			case IR is
					-- MUL AB
					when 	"10100100"		-- MUL AB
							=>
					case exe_state is
						when E0 =>
							exe_state <= E1;
							cpu_state <= T3;
						when E1 =>
							exe_state <= E2;
							cpu_state <= T3;
						when E2 =>
							exe_state <= E3;
							cpu_state <= T3;
						when E3 =>
							exe_state <= E4;
							cpu_state <= T3;
						when E4 =>
							exe_state <= E5;
							cpu_state <= T3;
						when E5 =>
							exe_state <= E6;
							cpu_state <= T3;
						when E6 =>
							exe_state <= E7;
							cpu_state <= T3;
						when E7 =>
							exe_state <= E8;
							cpu_state <= T3;
						when E8 =>
							exe_state <= E9;
							cpu_state <= T3;
						when E9 =>
							exe_state <= E10;
							cpu_state <= T3;
						when E10 =>
							exe_state <= E11;
							cpu_state <= T3;
						when E11 =>
							exe_state <= E0;
							cpu_state <= T4;
						when others =>
							exe_state <= E0;
							cpu_state <= T0;		
					end case;
					
				-- DIV AB
					when 	"10000100"		-- DIV AB
							=>   -- Since at least 17 cycles passed, store the result here
						case exe_state is
						when E0 =>
						-- If devided by zero
							if AR = "00000000" then 
								DR<= "--------";
								AR<= "--------";
								PSW(2)<='1';
							else
								DR <= quotient_o;
								AR <= remainder_o;
								PSW(2)<='0';
							end if;
							
							PSW(7) <='0';
							
							exe_state <= E1;
							cpu_state <= T3;
						when E1 =>
							-- Update new PSW
								i_rom_rd <= '0';
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_ram_addr <= xD0; 				-- Point to PSW
								i_ram_diByte <= PSW;	
								
							exe_state <= E2;
							cpu_state <= T3;
						when E2 =>
						
							-- Write quotient to Acc first
								i_rom_rd <= '0';
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Write quotient to Acc First
								i_ram_addr <= xE0;
								i_ram_dibyte <= DR;
								
							exe_state <= E3;
							cpu_state <= T3;
						when E3 =>
						
							-- Write remainder to B now
								i_rom_rd <= '0';
								i_ram_wrByte <= '1'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';				-- Write Remainder to B
								i_ram_addr <= xF0;
								i_ram_dibyte <= AR;
								
							exe_state <= E4;
							cpu_state <= T3;
						when E4 =>
						
							-- Disable all memory
								i_ram_wrByte <= '0'; 
								i_ram_rdByte <= '0'; 
								i_ram_wrBit <= '0'; 
								i_ram_rdBit <= '0';
								i_rom_rd <= '0';	
						
							exe_state <= E5;
							cpu_state <= T3;
						when E5 =>
							exe_state <= E6;
							cpu_state <= T3;
						when E6 =>
							exe_state <= E7;
							cpu_state <= T3;
						when E7 =>
							exe_state <= E8;
							cpu_state <= T3;
						when E8 =>
							exe_state <= E9;
							cpu_state <= T3;
						when E9 =>
							exe_state <= E10;
							cpu_state <= T3;
						when E10 =>
							exe_state <= E11;
							cpu_state <= T3;
						when E11 =>
							exe_state <= E0;
							cpu_state <= T4;
						when others =>
							exe_state <= E0;
							cpu_state <= T0;		
					end case;
				when others => 
					exe_state <= E0;
					cpu_state <= T0;	
			end case;
		when T4 =>
			case IR is
				-- DIV AB
					when 	"10000100"		-- DIV AB
							=>
					case exe_state is
						when E0 =>
							exe_state <= E1;
							cpu_state <= T4;
						when E1 =>
							exe_state <= E2;
							cpu_state <= T4;
						when E2 =>
							exe_state <= E3;
							cpu_state <= T4;
						when E3 =>
							exe_state <= E4;
							cpu_state <= T4;
						when E4 =>
							exe_state <= E5;
							cpu_state <= T4;
						when E5 =>
							exe_state <= E6;
							cpu_state <= T4;
						when E6 =>
							exe_state <= E7;
							cpu_state <= T4;
						when E7 =>
							exe_state <= E8;
							cpu_state <= T4;
						when E8 =>
							exe_state <= E9;
							cpu_state <= T4;
						when E9 =>
							exe_state <= E10;
							cpu_state <= T4;
						when E10 =>
							exe_state <= E11;
							cpu_state <= T4;
						when E11 =>
							exe_state <= E0;
							cpu_state <= T0;
						when others =>
							exe_state <= E0;
							cpu_state <= T0;		
					end case;
					
					-- MUL AB
					when 	"10100100"		-- MUL AB
							=>
					case exe_state is
						when E0 =>
							exe_state <= E1;
							cpu_state <= T4;
						when E1 =>
							exe_state <= E2;
							cpu_state <= T4;
						when E2 =>
							exe_state <= E3;
							cpu_state <= T4;
						when E3 =>
							exe_state <= E4;
							cpu_state <= T4;
						when E4 =>
							exe_state <= E5;
							cpu_state <= T4;
						when E5 =>
							exe_state <= E6;
							cpu_state <= T4;
						when E6 =>
							exe_state <= E7;
							cpu_state <= T4;
						when E7 =>
							exe_state <= E8;
							cpu_state <= T4;
						when E8 =>
							exe_state <= E9;
							cpu_state <= T4;
						when E9 =>
							exe_state <= E10;
							cpu_state <= T4;
						when E10 =>
							exe_state <= E11;
							cpu_state <= T4;
						when E11 =>
							exe_state <= E0;
							cpu_state <= T0;
						when others =>
							exe_state <= E0;
							cpu_state <= T0;		
					end case;
				when others => 
					exe_state <= E0;
					cpu_state <= T0;	
			end case;
		when others => 
			exe_state <= E0;
			cpu_state <= T0;
		end case; --cpu_state
end if;
end process;
end seq_arch;

-------------------------------------------------------------------------------

-- end of file --
